package cn.edu.my.regression.linear.unary;

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;

import cn.edu.my.regression.model.TradeFundFlowDirection;
import cn.edu.my.regression.service.TradeFundFlowDirectionService;
import cn.edu.my.regression.service.impl.TradeFundFlowDirectionServiceImpl;

public class UnaryLinearRegression {
	private double totalX;			//x的总和
	private double totalY;			//y的总和
	private double totalXX;			//x的二次方的总和
	private double totalXY;			//x乘y的总和
	private double totalYY;			//y的二次方的总和
	private double averageX;		//x的平均值
	private double averageY;		//y的平均值
	private double standardDeviationX;	//x的标准差
	private double standardDeviationY;	//y的标准差
	private double covarianceXY;		//x与 y的协方差
	private double lineaCorrelationCoefficient;	//直线相关系数
	private double a,b;							//系数
	private double surplusVariance;				//剩余方差
	private double estimatStandardError;		//回归估计标准误差
	private double determinationCoefficient;	//判定系数
	
	private TradeFundFlowDirectionService tradeFundFlowDirectionService;
	private List<TradeFundFlowDirection> tradeFundFlowDirectionList;
	private List<UnaryDataPoint> unaryDataPointList;						//坐标点的集合，包括x值和y值
	
	public UnaryLinearRegression() {
	}
	
	public UnaryLinearRegression(List<UnaryDataPoint> unaryDataPointList) {
		this.unaryDataPointList=unaryDataPointList;
	}
	
	public void obtainUnaryLinearRegression(){
		tradeFundFlowDirectionService=new TradeFundFlowDirectionServiceImpl();
		tradeFundFlowDirectionList = tradeFundFlowDirectionService.readTradeFundFlowDirectionList();
		unaryDataPointList=new ArrayList<UnaryDataPoint>();
		for (int i = 0; i < tradeFundFlowDirectionList.size(); i++) {
			UnaryDataPoint unaryDataPoint=new UnaryDataPoint();
			unaryDataPoint.setX(tradeFundFlowDirectionList.get(i).getSuperLargeSheetNetInflowPercentage());
			unaryDataPoint.setY(tradeFundFlowDirectionList.get(i).getUpDownRange());
			unaryDataPointList.add(unaryDataPoint);
		}
		
		//x的总和
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			totalX += unaryDataPointList.get(i).getX();
		}
		System.out.println("totalX:		" + totalX);
		
		//x的平均值
		averageX = totalX / unaryDataPointList.size();
		System.out.println("averageX:	" + averageX);
		
		//y的总和
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			totalY += unaryDataPointList.get(i).getY();
		}
		System.out.println("totalY:		" + totalY);
		
		//y的平均值
		averageY = totalY / unaryDataPointList.size();
		System.out.println("averageY:	" + averageY);
		
		//x的二次方的总和
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			totalXX += unaryDataPointList.get(i).getX()*unaryDataPointList.get(i).getX();
		}
		System.out.println("totalXX:	" + totalXX);
		
		//x乘y的总和
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			totalXY += unaryDataPointList.get(i).getX()*unaryDataPointList.get(i).getY();
		}
		System.out.println("totalXY:	" + totalXY);
		
		//y的二次方的总和
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			totalYY += unaryDataPointList.get(i).getY()*unaryDataPointList.get(i).getY();
		}
		System.out.println("totalYY:	" + totalYY);
		
		//x的标准差
		double standardDeviationXTemp=0;
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			standardDeviationXTemp+=Math.pow(unaryDataPointList.get(i).getX()-averageX,2);
		}
		standardDeviationX = Math.sqrt(standardDeviationXTemp/unaryDataPointList.size());
		System.out.println("standardDeviationX:	" + standardDeviationX);
		
		//Y的标准差
		double standardDeviationYTemp=0;
		for (int i = 0; i < unaryDataPointList.size(); i++) {
			standardDeviationYTemp+=Math.pow(unaryDataPointList.get(i).getY()-averageY,2);
		}
		standardDeviationY = Math.sqrt(standardDeviationYTemp/unaryDataPointList.size());
		System.out.println("standardDeviationY:	" + standardDeviationY);
		
		//x与 y的协方差
		double covarianceXYTemp=0;
		for (int i = 0; i<unaryDataPointList.size(); i++) {
			covarianceXYTemp+=(unaryDataPointList.get(i).getX()-averageX)*(unaryDataPointList.get(i).getY()-averageY);
		}
		covarianceXY = covarianceXYTemp/unaryDataPointList.size();
		System.out.println("covarianceXY:	" + covarianceXY);
		
		//直线相关系数
		lineaCorrelationCoefficient=covarianceXY/(standardDeviationX*standardDeviationY);
		System.out.println("lineaCorrelationCoefficient:	" + lineaCorrelationCoefficient);
		
		//直线相关系数的取值含义
		if(lineaCorrelationCoefficient>0){
			System.out.println("x与y是正相关");
		}else if(lineaCorrelationCoefficient<0){
			System.out.println("x与y是负相关");
		}else if(Math.abs(lineaCorrelationCoefficient)==1){
			System.out.println("x与y是完全相关");
		}else if(Math.abs(lineaCorrelationCoefficient)!=1){
			System.out.println("x与y是完全不相关");
			return;
		}
		
		//b
		b=lineaCorrelationCoefficient*(standardDeviationY/standardDeviationX);
		System.out.println("b:	" + b);
		
		//a
		a=averageY-b*averageX;
		System.out.println("a:	" + a);
		
		//一元线性回归方程
		System.out.println("y=" + round(a,2) + "+" + round(b,2) + "x");
		
		//剩余方差
		double surplusVarianceTemp=0;
		for(int i=0;i<unaryDataPointList.size();i++){
			surplusVarianceTemp+=Math.pow(unaryDataPointList.get(i).getY()-(b+a*unaryDataPointList.get(i).getX()),2);
		}
		surplusVariance=surplusVarianceTemp/(unaryDataPointList.size()-2);
		System.out.println("surplusVariance:	" + surplusVariance);
		
		//回归估计标准误差
		estimatStandardError=Math.sqrt(surplusVariance);
		System.out.println("estimatStandardError:	" + estimatStandardError);
		
		//判定系数
		determinationCoefficient=1-(Math.pow(estimatStandardError,2)/Math.pow(standardDeviationY,2));
		System.out.println("determinationCoefficient:	" + determinationCoefficient);
	}
	
	private double round(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	public List<UnaryDataPoint> getUnaryDataPointList() {
		return unaryDataPointList;
	}
	public void setUnaryDataPointList(List<UnaryDataPoint> unaryDataPointList) {
		this.unaryDataPointList = unaryDataPointList;
	}
	public double getAverageX() {
		return averageX;
	}
	public void setAverageX(double averageX) {
		this.averageX = averageX;
	}
	public double getAverageY() {
		return averageY;
	}
	public void setAverageY(double averageY) {
		this.averageY = averageY;
	}
	public double getTotalX() {
		return totalX;
	}
	public void setTotalX(double totalX) {
		this.totalX = totalX;
	}
	public double getTotalY() {
		return totalY;
	}
	public void setTotalY(double totalY) {
		this.totalY = totalY;
	}
	public double getTotalXX() {
		return totalXX;
	}
	public void setTotalXX(double totalXX) {
		this.totalXX = totalXX;
	}
	public double getTotalXY() {
		return totalXY;
	}
	public void setTotalXY(double totalXY) {
		this.totalXY = totalXY;
	}
	public double getTotalYY() {
		return totalYY;
	}
	public void setTotalYY(double totalYY) {
		this.totalYY = totalYY;
	}
	public double getStandardDeviationX() {
		return standardDeviationX;
	}
	public void setStandardDeviationX(double standardDeviationX) {
		this.standardDeviationX = standardDeviationX;
	}
	public double getStandardDeviationY() {
		return standardDeviationY;
	}
	public void setStandardDeviationY(double standardDeviationY) {
		this.standardDeviationY = standardDeviationY;
	}
	public double getCovarianceXY() {
		return covarianceXY;
	}
	public void setCovarianceXY(double covarianceXY) {
		this.covarianceXY = covarianceXY;
	}
	public double getLineaCorrelationCoefficient() {
		return lineaCorrelationCoefficient;
	}
	public void setLineaCorrelationCoefficient(double lineaCorrelationCoefficient) {
		this.lineaCorrelationCoefficient = lineaCorrelationCoefficient;
	}
	public double getSurplusVariance() {
		return surplusVariance;
	}
	public void setSurplusVariance(double surplusVariance) {
		this.surplusVariance = surplusVariance;
	}
	public double getEstimatStandardError() {
		return estimatStandardError;
	}
	public void setEstimatStandardError(double estimatStandardError) {
		this.estimatStandardError = estimatStandardError;
	}
	public double getDeterminationCoefficient() {
		return determinationCoefficient;
	}
	public void setDeterminationCoefficient(double determinationCoefficient) {
		this.determinationCoefficient = determinationCoefficient;
	}
}
